Effects on patient analysis of using different detection thresholds

Patient data - used for all analyses

library(tidyverse)
library(cowplot)
library(randomForest)
library(pROC)
library(pheatmap)
library(epitools)
library(glmnet)
library(nlme)
library(ggforce)
library(gggenes)
library(viridis)
patient_data<-read.csv("sample_and_patient_data.csv") %>% mutate(MCoVNumber=str_remove(mcov_id, "-")) %>% mutate(collection_date=as.Date(COLLECTION_DT, "%m/%d/%y")) %>% mutate(collection_month=format(as.Date(collection_date), "%Y-%m")) %>%
  mutate(CT=ifelse(INSTRUMENT_RESULT<50, INSTRUMENT_RESULT, NA_integer_)) %>% mutate(vaccine_status=if_else(Vaccine_Status=="No vaccine"|Vaccine_Status==">7 days past 1st Vaccine",0,1)) %>%
  mutate(age18under=if_else(Age_Group=="00-17",1,0)) %>% mutate(age18to54=if_else(Age_Group=="18-54",1,0)) %>% mutate(age55plus=if_else(Age_Group=="55-64"|Age_Group=="65+",1,0)) %>%
  select(MCoVNumber, collection_date, collection_month, run=run_group, CT, ordering_clinic=ORDERING_CLINIC_TYPE,pui=PUI, age18under, age18to54, age55plus, sex=SEX, ethnicity=Ethnicity, obesity=Obesity_YN, chronic_lung_disease=Chronic_Lung_Disease_YN, chronic_liver_disease=Chronic_Liver_Disease_YN, surveillance_sample=IS_SURVEILLANCE, chronic_heart_disease=Chronic_Heart_Disease_YN,chronic_kidney_disease=Chronic_Kidney_Disease_YN, hypertension=Hypertension_YN, diabetes=Diabetes_YN, cancer=Cancer_YN, hiv=HIV_YN, transplant_patient=Transplant_Patient, vaccine_status, admitted_hospital=Admitted_YN, highest_level=HIGHEST_LEVEL_OF_CARE, max_respiratory_support=MaxRespiratorySupport, mAb=mAb_YN, plasma=Plasma_YN)

factor_columns<- c("collection_month","run","ordering_clinic","pui","age18under","age18to54", "age55plus","sex","ethnicity","obesity","surveillance_sample", "chronic_lung_disease","chronic_liver_disease","chronic_heart_disease","chronic_kidney_disease","hypertension","diabetes","cancer","hiv","transplant_patient","vaccine_status","admitted_hospital","highest_level","max_respiratory_support","mAb","plasma") 

patient_data[factor_columns]<-lapply(patient_data[factor_columns], factor)

Alternate Dataset 1: 2% MAF, 200x coverage, min. 100 reads to call minor variant

#load file and tally minor variant richness
minor_variant_sites_threshold<-read.csv('minor_variants_filtered_200x0.02_100.csv') 
mcov_samples_filtered<-mcov_samples %>% filter(!run %in% runs_to_drop) %>% 
  filter(qc_status=="pass") %>% filter(!MCoVNumber %in% nextclade_bad_samples) %>% filter(scorpio_call!="Omicron (BA.1-like)") %>% 
 ##### #main coverage criterion for fair comparisons: X depth over Y percent of the genome
  filter(fraction_200x_coverage>=0.98) %>% droplevels()
n_var<-minor_variant_sites_threshold %>% group_by(MCoVNumber) %>% tally() 
samples_n_var<-mcov_samples_filtered %>% left_join(n_var) %>% arrange(COLLECTION_DT) %>% mutate(n_var=replace_na(n, 0))
Joining, by = "MCoVNumber"
for_patient_analysis<-samples_n_var %>% filter(INSTRUMENT_RESULT<26)  %>% select(MCoVNumber, n_var, scorpio_call) 
for_patient_analysis %>% pull(n_var) %>% summary
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   1.000   2.722   3.000 140.000 
for_patient_analysis %>% nrow() 
[1] 5798
median_var<-for_patient_analysis %>% pull(n_var) %>% median()
#add patient metadata to sample minor variant richness
p<-left_join(for_patient_analysis, patient_data) %>% droplevels() %>% mutate(vocAlpha=if_else(startsWith(scorpio_call, "Alpha"),1,0), vocDelta=if_else(startsWith(scorpio_call, "Delta"),1,0)) %>% mutate(vocAlpha=as.factor(vocAlpha), vocDelta=as.factor(vocDelta))
Joining, by = "MCoVNumber"
#Random Forest model of patient characteristics for classifying low-CT samples as having high or low minor variant richness
p <- p %>% mutate(var_level=if_else(n_var<=median_var, "low","high")) %>% mutate(var_level=as.factor(var_level)) 

p_select <- p  %>% select(age18under, age18to54, age55plus, sex, ethnicity, chronic_lung_disease, chronic_liver_disease, chronic_kidney_disease, chronic_heart_disease, hypertension, diabetes, cancer, obesity, transplant_patient, plasma, mAb, vaccine_status, admitted_hospital,surveillance_sample, var_level) 

p.rf<-randomForest(var_level~.,
                               data=p_select, 
                               ntree=1000,
                                mtry=5,
                               importance = T) 

importance.randomForest <- as.data.frame(randomForest::importance(p.rf))

importance.randomForest<-importance.randomForest %>% arrange(desc(MeanDecreaseAccuracy))
importance.randomForest

rf.roc<-roc(p_select$var_level,p.rf$votes[,2], levels=c(case="high",control="low"))
Setting direction: controls < cases
auc(rf.roc)
Area under the curve: 0.5961

Association between patient hospitalization and high minor variant richness

categories<-p %>% mutate(minor_greater_0=if_else(n_var>0,'yes','no')) %>% mutate(minor_greater_5=if_else(n_var>5,'yes','no')) %>% mutate(minor_greater_10=if_else(n_var>10,'yes','no')) 
categories1<-categories %>% group_by(admitted_hospital, minor_greater_0) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_0)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories2<-categories %>% group_by(admitted_hospital, minor_greater_5) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_5)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories3<-categories %>% group_by(admitted_hospital, minor_greater_10) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_10)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
plot_grid(categories1, categories2, categories3, nrow=3)

hospitalization<-table(p$admitted_hospital,p$var_level) 
hospitalization
   
    high  low
  0 1302 2379
  1 1090 1027
chisq.test(hospitalization)

    Pearson's Chi-squared test with Yates' continuity correction

data:  hospitalization
X-squared = 143.39, df = 1, p-value < 2.2e-16
oddsratio(hospitalization, rev="columns")
$data
       
         low high Total
  0     2379 1302  3681
  1     1027 1090  2117
  Total 3406 2392  5798

$measure
   odds ratio with 95% C.I.
    estimate    lower    upper
  0 1.000000       NA       NA
  1 1.938966 1.739307 2.162093

$p.value
   two-sided
    midp.exact fisher.exact   chi.square
  0         NA           NA           NA
  1          0 6.637658e-33 3.452345e-33

$correction
[1] FALSE

attr(,"method")
[1] "median-unbiased estimate & mid-p exact CI"
#linear mixed-effect model with sequencing run as random effect
lme(log10(n_var+1) ~ CT*admitted_hospital, random=~1|run,
            data=p) %>% anova() 
hosp_altdata1<-p %>% ggplot(aes(x=CT, y=log10(n_var+1), color=admitted_hospital)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkred")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=10, y=2, label="Ct p<0.0001 \nhospitalization p<0.0001 \nCt*hospitalization p<0.0001") + theme(legend.position="bottom") + ylim(0,2.6)

Other ways of examining disease severity: vaccination status and healthcare worker surveillance

#when did most cases among vaccinated patients occur?
table(p$collection_month, p$vaccine_status)
         
             0    1
  2020-12 1478    0
  2021-01  883    0
  2021-02  351    1
  2021-03  379    7
  2021-04  265   12
  2021-05  180   16
  2021-06   68   10
  2021-07  302  122
  2021-08  873  370
  2021-09  149   93
  2021-10   71   48
  2021-11   62   58
vax_status_subset<- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>% 
  filter(collection_date>="2021-07-01") %>% filter(admitted_hospital==0) 
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*vaccine_status, random=~1|run,
            data=vax_status_subset) %>% anova() 
NA
#to see effect of vaccination (as a correlate of disease severity): limit to later than July and only non-hospitalized patients
vax_altdata1<-vax_status_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=vaccine_status)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","lightblue")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=14, y=2, label="Ct p<0.0001 \nvaccination p=0.0119 \nCt*vaccination p=0.055") + theme(legend.position="bottom") + ylim(0,2.6)
#healthcare worker surveillance (presumed mostly asymptomatic) vs non-hospitalized patients (presumed mostly symptomatic)
surv_subset <- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>%
  filter(admitted_hospital==0) %>% filter(!(surveillance_sample==1 & pui=="PUI")) #exclude HCW who were patients
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*surveillance_sample, random=~1|run,
            data=surv_subset) %>% anova() 
hcw_altdata1<-surv_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=surveillance_sample)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkgreen")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=12, y=2, label="Ct p<0.0001 \nHCW surveillance p=0.007 \nCt*surveillance p=0.0076")+ theme(legend.position="bottom") + ylim(0,2.6)
#LASSO regression model including all sample and patient characteristics to explain minor variant richness
p_sub<- p %>% left_join(mcov_samples) #to add info about coverage
Joining, by = c("MCoVNumber", "scorpio_call", "run")
y<-log10(p_sub$n_var+1)
x<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital','vaccine_status','vocAlpha','vocDelta','collection_month','surveillance_sample','CT','median_coverage','run')])

cv_model <- cv.glmnet(x, y, alpha = 1, nfolds=100)
plot(cv_model) 

best_model <- glmnet(x, y, alpha = 1, lambda = cv_model$lambda.min)
best_model$dev.ratio
[1] 0.1432548
lasso1_altdata1<-coef(best_model) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="gray") + theme_bw() + ylab("Factor") + xlab("Coefficient")
#same model excluding any factors with a temporal signal (VOC, vaccination, collection month, run)
y2<-log10(p_sub$n_var+1)
x2<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital', 'surveillance_sample', 'CT', 'median_coverage')])

cv_model_2 <- cv.glmnet(x2, y2, alpha = 1, nfolds=100)
plot(cv_model_2) 

best_model_2 <- glmnet(x2, y2, alpha = 1, lambda = cv_model$lambda.min)
best_model_2$dev.ratio
[1] 0.1144788
lasso2_altdata1<-coef(best_model_2) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="black") + theme_bw() + ylab("Factor") + xlab("Coefficient")
title <- ggdraw() + 
  draw_label(
    "Alternate dataset 1",
    fontface = 'bold',
    x = 0,
    hjust = 0)

all_plots_altdata1<-plot_grid(plot_grid(hosp_altdata1, vax_altdata1, hcw_altdata1, ncol=3), plot_grid(lasso1_altdata1, lasso2_altdata1, ncol=2), nrow=2, rel_heights = c(2,1))
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 3 rows containing missing values (geom_smooth).
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 10 rows containing missing values (geom_smooth).
alt_1<-plot_grid(title, all_plots_altdata1, nrow=2, rel_heights=c(0.1,1))

Alternate Dataset 2: 3% MAF, min 500x coverage, min 20 reads

#load file and tally minor variant richness
minor_variant_sites_threshold<-read.csv('minor_variants_filtered_500x0.03_20.csv') 
mcov_samples_filtered<-mcov_samples %>% filter(!run %in% runs_to_drop) %>% 
  filter(qc_status=="pass") %>% filter(!MCoVNumber %in% nextclade_bad_samples) %>% filter(scorpio_call!="Omicron (BA.1-like)") %>% 
 ##### #main coverage criterion for fair comparisons: X depth over Y percent of the genome
  filter(fraction_500x_coverage>=0.98) %>% droplevels()
n_var<-minor_variant_sites_threshold %>% group_by(MCoVNumber) %>% tally() 
samples_n_var<-mcov_samples_filtered %>% left_join(n_var) %>% arrange(COLLECTION_DT) %>% mutate(n_var=replace_na(n, 0))
Joining, by = "MCoVNumber"
for_patient_analysis<-samples_n_var %>% filter(INSTRUMENT_RESULT<26)  %>% select(MCoVNumber, n_var, scorpio_call) 
for_patient_analysis %>% pull(n_var) %>% summary
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   0.000   1.000   1.621   2.000  99.000 
for_patient_analysis %>% nrow() 
[1] 4869
median_var<-for_patient_analysis %>% pull(n_var) %>% median()
#add patient metadata to sample minor variant richness
p<-left_join(for_patient_analysis, patient_data) %>% droplevels() %>% mutate(vocAlpha=if_else(startsWith(scorpio_call, "Alpha"),1,0), vocDelta=if_else(startsWith(scorpio_call, "Delta"),1,0)) %>% mutate(vocAlpha=as.factor(vocAlpha), vocDelta=as.factor(vocDelta))
Joining, by = "MCoVNumber"
#Random Forest model of patient characteristics for classifying low-CT samples as having high or low minor variant richness
p <- p %>% mutate(var_level=if_else(n_var<=median_var, "low","high")) %>% mutate(var_level=as.factor(var_level)) 

p_select <- p  %>% select(age18under, age18to54, age55plus, sex, ethnicity, chronic_lung_disease, chronic_liver_disease, chronic_kidney_disease, chronic_heart_disease, hypertension, diabetes, cancer, obesity, transplant_patient, plasma, mAb, vaccine_status, admitted_hospital,surveillance_sample, var_level) 

p.rf<-randomForest(var_level~.,
                               data=p_select, 
                               ntree=1000,
                                mtry=5,
                               importance = T) 

importance.randomForest <- as.data.frame(randomForest::importance(p.rf))

importance.randomForest<-importance.randomForest %>% arrange(desc(MeanDecreaseAccuracy))
importance.randomForest

rf.roc<-roc(p_select$var_level,p.rf$votes[,2], levels=c(case="high",control="low"))
Setting direction: controls < cases
auc(rf.roc)
Area under the curve: 0.583

Association between patient hospitalization and high minor variant richness

categories<-p %>% mutate(minor_greater_0=if_else(n_var>0,'yes','no')) %>% mutate(minor_greater_5=if_else(n_var>5,'yes','no')) %>% mutate(minor_greater_10=if_else(n_var>10,'yes','no')) 
categories1<-categories %>% group_by(admitted_hospital, minor_greater_0) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_0)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories2<-categories %>% group_by(admitted_hospital, minor_greater_5) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_5)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories3<-categories %>% group_by(admitted_hospital, minor_greater_10) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_10)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
plot_grid(categories1, categories2, categories3, nrow=3)

hospitalization<-table(p$admitted_hospital,p$var_level) 
hospitalization
   
    high  low
  0  754 2428
  1  640 1047
chisq.test(hospitalization)

    Pearson's Chi-squared test with Yates' continuity correction

data:  hospitalization
X-squared = 108.74, df = 1, p-value < 2.2e-16
oddsratio(hospitalization, rev="columns")
$data
       
         low high Total
  0     2428  754  3182
  1     1047  640  1687
  Total 3475 1394  4869

$measure
   odds ratio with 95% C.I.
    estimate    lower   upper
  0 1.000000       NA      NA
  1 1.968102 1.731812 2.23668

$p.value
   two-sided
    midp.exact fisher.exact   chi.square
  0         NA           NA           NA
  1          0 4.812526e-25 1.305533e-25

$correction
[1] FALSE

attr(,"method")
[1] "median-unbiased estimate & mid-p exact CI"
#linear mixed-effect model with sequencing run as random effect
lme(log10(n_var+1) ~ CT*admitted_hospital, random=~1|run,
            data=p) %>% anova() 
hosp_altdata2<-p %>% ggplot(aes(x=CT, y=log10(n_var+1), color=admitted_hospital)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkred")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=10, y=1.75, label="Ct p<0.0001 \nhospitalization p<0.0001 \nCt*hospitalization p=0.0059") + theme(legend.position="bottom") + ylim(0,2.6)
hosp_altdata2
`geom_smooth()` using formula 'y ~ x'

vax_status_subset<- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>% 
  filter(collection_date>="2021-07-01") %>% filter(admitted_hospital==0) 
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*vaccine_status, random=~1|run,
            data=vax_status_subset) %>% anova() 
#to see effect of vaccination (as a correlate of disease severity): limit to later than July and only non-hospitalized patients
vax_altdata2<-vax_status_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=vaccine_status)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","lightblue")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=14, y=1.75, label="Ct p<0.0001 \nvaccination p=0.0671 \nCt*vaccination p=0.0226") + theme(legend.position="bottom") + ylim(0,2.6)
vax_altdata2
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 5 rows containing missing values (geom_smooth).

#healthcare worker surveillance (presumed mostly asymptomatic) vs non-hospitalized patients (presumed mostly symptomatic)
surv_subset <- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>%
  filter(admitted_hospital==0) %>% filter(!(surveillance_sample==1 & pui=="PUI")) #exclude HCW who were patients
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*surveillance_sample, random=~1|run,
            data=surv_subset) %>% anova() 
hcw_altdata2<-surv_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=surveillance_sample)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkgreen")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=12, y=1.75, label="Ct p<0.0001 \nHCW surveillance p=0.0077 \nCt*surveillance p=0.0001")+ theme(legend.position="bottom") + ylim(0,2.6)
hcw_altdata2
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 11 rows containing missing values (geom_smooth).

#LASSO regression model including all sample and patient characteristics to explain minor variant richness
p_sub<- p %>% left_join(mcov_samples) #to add info about coverage
Joining, by = c("MCoVNumber", "scorpio_call", "run")
y<-log10(p_sub$n_var+1)
x<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital','vaccine_status','vocAlpha','vocDelta','collection_month','surveillance_sample','CT','median_coverage','run')])

cv_model <- cv.glmnet(x, y, alpha = 1, nfolds=100)
plot(cv_model) 

best_model <- glmnet(x, y, alpha = 1, lambda = cv_model$lambda.min)
best_model$dev.ratio
[1] 0.1014136
lasso1_altdata2<-coef(best_model) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="gray") + theme_bw() + ylab("Factor") + xlab("Coefficient")
#same model excluding any factors with a temporal signal (VOC, vaccination, collection month, run)
y2<-log10(p_sub$n_var+1)
x2<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital', 'surveillance_sample', 'CT', 'median_coverage')])

cv_model_2 <- cv.glmnet(x2, y2, alpha = 1, nfolds=100)
plot(cv_model_2) 

best_model_2 <- glmnet(x2, y2, alpha = 1, lambda = cv_model$lambda.min)
best_model_2$dev.ratio
[1] 0.07680036
lasso2_altdata2<-coef(best_model_2) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="black") + theme_bw() + ylab("Factor") + xlab("Coefficient")
title <- ggdraw() + 
  draw_label(
    "Alternate dataset 2",
    fontface = 'bold',
    x = 0,
    hjust = 0)

all_plots_altdata2<-plot_grid(plot_grid(hosp_altdata2, vax_altdata2, hcw_altdata2, ncol=3), plot_grid(lasso1_altdata2, lasso2_altdata2, ncol=2), nrow=2, rel_heights = c(2,1))
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 5 rows containing missing values (geom_smooth).
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 11 rows containing missing values (geom_smooth).
alt_2<-plot_grid(title, all_plots_altdata2, nrow=2, rel_heights=c(0.1,1))
alt_2

Alternate Dataset 3: MAF 1%, minimum 1000x coverage

#load file and tally minor variant richness
minor_variant_sites_threshold<-read.csv('minor_variants_filtered_1000x0.01.csv') 
mcov_samples_filtered<-mcov_samples %>% filter(!run %in% runs_to_drop) %>% 
  filter(qc_status=="pass") %>% filter(!MCoVNumber %in% nextclade_bad_samples) %>% filter(scorpio_call!="Omicron (BA.1-like)") %>% 
 ##### #main coverage criterion for fair comparisons: X depth over Y percent of the genome
  filter(fraction_1000x_coverage>=0.98) %>% droplevels()
n_var<-minor_variant_sites_threshold %>% group_by(MCoVNumber) %>% tally() 
samples_n_var<-mcov_samples_filtered %>% left_join(n_var) %>% arrange(COLLECTION_DT) %>% mutate(n_var=replace_na(n, 0))
Joining, by = "MCoVNumber"
for_patient_analysis<-samples_n_var %>% filter(INSTRUMENT_RESULT<26)  %>% select(MCoVNumber, n_var, scorpio_call) 
for_patient_analysis %>% pull(n_var) %>% summary
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  0.000   3.000   6.000   8.193  10.000 275.000 
for_patient_analysis %>% nrow() 
[1] 3486
median_var<-for_patient_analysis %>% pull(n_var) %>% median()
#add patient metadata to sample minor variant richness
p<-left_join(for_patient_analysis, patient_data) %>% droplevels() %>% mutate(vocAlpha=if_else(startsWith(scorpio_call, "Alpha"),1,0), vocDelta=if_else(startsWith(scorpio_call, "Delta"),1,0)) %>% mutate(vocAlpha=as.factor(vocAlpha), vocDelta=as.factor(vocDelta))
Joining, by = "MCoVNumber"
#Random Forest model of patient characteristics for classifying low-CT samples as having high or low minor variant richness
p <- p %>% mutate(var_level=if_else(n_var<=median_var, "low","high")) %>% mutate(var_level=as.factor(var_level)) 

p_select <- p  %>% select(age18under, age18to54, age55plus, sex, ethnicity, chronic_lung_disease, chronic_liver_disease, chronic_kidney_disease, chronic_heart_disease, hypertension, diabetes, cancer, obesity, transplant_patient, plasma, mAb, vaccine_status, admitted_hospital,surveillance_sample, var_level) 

p.rf<-randomForest(var_level~.,
                               data=p_select, 
                               ntree=1000,
                                mtry=5,
                               importance = T) 

importance.randomForest <- as.data.frame(randomForest::importance(p.rf))

importance.randomForest<-importance.randomForest %>% arrange(desc(MeanDecreaseAccuracy))
importance.randomForest

rf.roc<-roc(p_select$var_level,p.rf$votes[,2], levels=c(case="high",control="low"))
Setting direction: controls < cases
auc(rf.roc)
Area under the curve: 0.5994

Association between patient hospitalization and high minor variant richness

categories<-p %>% mutate(minor_greater_0=if_else(n_var>0,'yes','no')) %>% mutate(minor_greater_5=if_else(n_var>5,'yes','no')) %>% mutate(minor_greater_10=if_else(n_var>10,'yes','no')) 
categories1<-categories %>% group_by(admitted_hospital, minor_greater_0) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_0)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories2<-categories %>% group_by(admitted_hospital, minor_greater_5) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_5)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
categories3<-categories %>% group_by(admitted_hospital, minor_greater_10) %>% tally() %>% ggplot(aes(x=admitted_hospital, y=n, fill=minor_greater_10)) + geom_bar(stat="identity") + scale_fill_manual(values=c("gray","black")) + theme_bw()
plot_grid(categories1, categories2, categories3, nrow=3)

hospitalization<-table(p$admitted_hospital,p$var_level) 
hospitalization
   
    high  low
  0  847 1478
  1  640  521
chisq.test(hospitalization)

    Pearson's Chi-squared test with Yates' continuity correction

data:  hospitalization
X-squared = 109.87, df = 1, p-value < 2.2e-16
oddsratio(hospitalization, rev="columns")
$data
       
         low high Total
  0     1478  847  2325
  1      521  640  1161
  Total 1999 1487  3486

$measure
   odds ratio with 95% C.I.
    estimate   lower   upper
  0  1.00000      NA      NA
  1  2.14292 1.85737 2.47349

$p.value
   two-sided
    midp.exact fisher.exact   chi.square
  0         NA           NA           NA
  1          0 1.182952e-25 7.106677e-26

$correction
[1] FALSE

attr(,"method")
[1] "median-unbiased estimate & mid-p exact CI"
#linear mixed-effect model with sequencing run as random effect
lme(log10(n_var+1) ~ CT*admitted_hospital, random=~1|run,
            data=p) %>% anova() 
hosp_altdata3<-p %>% ggplot(aes(x=CT, y=log10(n_var+1), color=admitted_hospital)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkred")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=10, y=2, label="Ct p<0.0001 \nhospitalization p<0.0001 \nCt*hospitalization p<0.0001") + theme(legend.position="bottom") + ylim(0,2.6)
hosp_altdata3
`geom_smooth()` using formula 'y ~ x'

vax_status_subset<- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>% 
  filter(collection_date>="2021-07-01") %>% filter(admitted_hospital==0) 
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*vaccine_status, random=~1|run,
            data=vax_status_subset) %>% anova() 
NA
#to see effect of vaccination (as a correlate of disease severity): limit to later than July and only non-hospitalized patients
vax_altdata3<-vax_status_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=vaccine_status)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","lightblue")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=14, y=2, label="Ct p<0.0001 \nvaccination p=0.1098 \nCt*vaccination p=0.56") + theme(legend.position="bottom") + ylim(0,2.6)
vax_altdata3
`geom_smooth()` using formula 'y ~ x'

#healthcare worker surveillance (presumed mostly asymptomatic) vs non-hospitalized patients (presumed mostly symptomatic)
surv_subset <- samples_n_var %>% filter(INSTRUMENT_RESULT<35)  %>% select(MCoVNumber, n_var, scorpio_call) %>% left_join(patient_data) %>%
  filter(admitted_hospital==0) %>% filter(!(surveillance_sample==1 & pui=="PUI")) #exclude HCW who were patients
Joining, by = "MCoVNumber"
lme(log10(n_var+1) ~ CT*surveillance_sample, random=~1|run,
            data=surv_subset) %>% anova() 
hcw_altdata3<-surv_subset %>% ggplot(aes(x=CT, y=log10(n_var+1), color=surveillance_sample)) + geom_point(alpha=0.5) + scale_color_manual(values=c("black","darkgreen")) + geom_smooth(method=lm) + theme_bw() + annotate("text", x=12, y=2, label="Ct p<0.0001 \nHCW surveillance p=0.449 \nCt*surveillance p=0.0019")+ theme(legend.position="bottom") + ylim(0,2.6)
hcw_altdata3
`geom_smooth()` using formula 'y ~ x'

#LASSO regression model including all sample and patient characteristics to explain minor variant richness
p_sub<- p %>% left_join(mcov_samples) #to add info about coverage
Joining, by = c("MCoVNumber", "scorpio_call", "run")
y<-log10(p_sub$n_var+1)
x<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital','vaccine_status','vocAlpha','vocDelta','collection_month','surveillance_sample','CT','median_coverage','run')])

cv_model <- cv.glmnet(x, y, alpha = 1, nfolds=100)
plot(cv_model) 

best_model <- glmnet(x, y, alpha = 1, lambda = cv_model$lambda.min)
best_model$dev.ratio
[1] 0.2848387
lasso1_altdata3<-coef(best_model) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="gray") + theme_bw() + ylab("Factor") + xlab("Coefficient")
#same model excluding any factors with a temporal signal (VOC, vaccination, collection month, run)
y2<-log10(p_sub$n_var+1)
x2<-data.matrix(p_sub[, c('age18under','age55plus','sex','chronic_lung_disease', 'chronic_liver_disease', 'chronic_kidney_disease', 'chronic_heart_disease', 'hypertension', 'diabetes', 'cancer', 'obesity', 'plasma', 'mAb', 'admitted_hospital', 'surveillance_sample', 'CT', 'median_coverage')])

cv_model_2 <- cv.glmnet(x2, y2, alpha = 1, nfolds=100)
plot(cv_model_2) 

best_model_2 <- glmnet(x2, y2, alpha = 1, lambda = cv_model$lambda.min)
best_model_2$dev.ratio
[1] 0.1660055
lasso2_altdata3<-coef(best_model_2) %>% as.matrix() %>% data.frame() %>% rownames_to_column() %>% rename(factor=rowname, coefficient=s0) %>% filter(factor!="(Intercept)") %>% arrange(desc(coefficient)) %>% ggplot(aes(x=coefficient, y=fct_reorder(factor,coefficient))) + geom_bar(stat="identity", fill="#E2D200", color="black") + theme_bw() + ylab("Factor") + xlab("Coefficient")
title <- ggdraw() + 
  draw_label(
    "Alternate dataset 3",
    fontface = 'bold',
    x = 0,
    hjust = 0)

all_plots_altdata3<-plot_grid(plot_grid(hosp_altdata3, vax_altdata3, hcw_altdata3, ncol=3), plot_grid(lasso1_altdata3, lasso2_altdata3, ncol=2), nrow=2, rel_heights = c(2,1))
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using formula 'y ~ x'
alt_3<-plot_grid(title, all_plots_altdata3, nrow=2, rel_heights=c(0.1,1))
alt_3

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBFZmZlY3RzIG9uIHBhdGllbnQgYW5hbHlzaXMgb2YgdXNpbmcgZGlmZmVyZW50IGRldGVjdGlvbiB0aHJlc2hvbGRzCiMjIFBhdGllbnQgZGF0YSAtIHVzZWQgZm9yIGFsbCBhbmFseXNlcwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KHBST0MpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkoZXBpdG9vbHMpCmxpYnJhcnkoZ2xtbmV0KQpsaWJyYXJ5KG5sbWUpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShnZ2dlbmVzKQpsaWJyYXJ5KHZpcmlkaXMpCmBgYAoKYGBge3J9CnBhdGllbnRfZGF0YTwtcmVhZC5jc3YoInNhbXBsZV9hbmRfcGF0aWVudF9kYXRhLmNzdiIpICU+JSBtdXRhdGUoTUNvVk51bWJlcj1zdHJfcmVtb3ZlKG1jb3ZfaWQsICItIikpICU+JSBtdXRhdGUoY29sbGVjdGlvbl9kYXRlPWFzLkRhdGUoQ09MTEVDVElPTl9EVCwgIiVtLyVkLyV5IikpICU+JSBtdXRhdGUoY29sbGVjdGlvbl9tb250aD1mb3JtYXQoYXMuRGF0ZShjb2xsZWN0aW9uX2RhdGUpLCAiJVktJW0iKSkgJT4lCiAgbXV0YXRlKENUPWlmZWxzZShJTlNUUlVNRU5UX1JFU1VMVDw1MCwgSU5TVFJVTUVOVF9SRVNVTFQsIE5BX2ludGVnZXJfKSkgJT4lIG11dGF0ZSh2YWNjaW5lX3N0YXR1cz1pZl9lbHNlKFZhY2NpbmVfU3RhdHVzPT0iTm8gdmFjY2luZSJ8VmFjY2luZV9TdGF0dXM9PSI+NyBkYXlzIHBhc3QgMXN0IFZhY2NpbmUiLDAsMSkpICU+JQogIG11dGF0ZShhZ2UxOHVuZGVyPWlmX2Vsc2UoQWdlX0dyb3VwPT0iMDAtMTciLDEsMCkpICU+JSBtdXRhdGUoYWdlMTh0bzU0PWlmX2Vsc2UoQWdlX0dyb3VwPT0iMTgtNTQiLDEsMCkpICU+JSBtdXRhdGUoYWdlNTVwbHVzPWlmX2Vsc2UoQWdlX0dyb3VwPT0iNTUtNjQifEFnZV9Hcm91cD09IjY1KyIsMSwwKSkgJT4lCiAgc2VsZWN0KE1Db1ZOdW1iZXIsIGNvbGxlY3Rpb25fZGF0ZSwgY29sbGVjdGlvbl9tb250aCwgcnVuPXJ1bl9ncm91cCwgQ1QsIG9yZGVyaW5nX2NsaW5pYz1PUkRFUklOR19DTElOSUNfVFlQRSxwdWk9UFVJLCBhZ2UxOHVuZGVyLCBhZ2UxOHRvNTQsIGFnZTU1cGx1cywgc2V4PVNFWCwgZXRobmljaXR5PUV0aG5pY2l0eSwgb2Jlc2l0eT1PYmVzaXR5X1lOLCBjaHJvbmljX2x1bmdfZGlzZWFzZT1DaHJvbmljX0x1bmdfRGlzZWFzZV9ZTiwgY2hyb25pY19saXZlcl9kaXNlYXNlPUNocm9uaWNfTGl2ZXJfRGlzZWFzZV9ZTiwgc3VydmVpbGxhbmNlX3NhbXBsZT1JU19TVVJWRUlMTEFOQ0UsIGNocm9uaWNfaGVhcnRfZGlzZWFzZT1DaHJvbmljX0hlYXJ0X0Rpc2Vhc2VfWU4sY2hyb25pY19raWRuZXlfZGlzZWFzZT1DaHJvbmljX0tpZG5leV9EaXNlYXNlX1lOLCBoeXBlcnRlbnNpb249SHlwZXJ0ZW5zaW9uX1lOLCBkaWFiZXRlcz1EaWFiZXRlc19ZTiwgY2FuY2VyPUNhbmNlcl9ZTiwgaGl2PUhJVl9ZTiwgdHJhbnNwbGFudF9wYXRpZW50PVRyYW5zcGxhbnRfUGF0aWVudCwgdmFjY2luZV9zdGF0dXMsIGFkbWl0dGVkX2hvc3BpdGFsPUFkbWl0dGVkX1lOLCBoaWdoZXN0X2xldmVsPUhJR0hFU1RfTEVWRUxfT0ZfQ0FSRSwgbWF4X3Jlc3BpcmF0b3J5X3N1cHBvcnQ9TWF4UmVzcGlyYXRvcnlTdXBwb3J0LCBtQWI9bUFiX1lOLCBwbGFzbWE9UGxhc21hX1lOKQoKZmFjdG9yX2NvbHVtbnM8LSBjKCJjb2xsZWN0aW9uX21vbnRoIiwicnVuIiwib3JkZXJpbmdfY2xpbmljIiwicHVpIiwiYWdlMTh1bmRlciIsImFnZTE4dG81NCIsICJhZ2U1NXBsdXMiLCJzZXgiLCJldGhuaWNpdHkiLCJvYmVzaXR5Iiwic3VydmVpbGxhbmNlX3NhbXBsZSIsICJjaHJvbmljX2x1bmdfZGlzZWFzZSIsImNocm9uaWNfbGl2ZXJfZGlzZWFzZSIsImNocm9uaWNfaGVhcnRfZGlzZWFzZSIsImNocm9uaWNfa2lkbmV5X2Rpc2Vhc2UiLCJoeXBlcnRlbnNpb24iLCJkaWFiZXRlcyIsImNhbmNlciIsImhpdiIsInRyYW5zcGxhbnRfcGF0aWVudCIsInZhY2NpbmVfc3RhdHVzIiwiYWRtaXR0ZWRfaG9zcGl0YWwiLCJoaWdoZXN0X2xldmVsIiwibWF4X3Jlc3BpcmF0b3J5X3N1cHBvcnQiLCJtQWIiLCJwbGFzbWEiKSAKCnBhdGllbnRfZGF0YVtmYWN0b3JfY29sdW1uc108LWxhcHBseShwYXRpZW50X2RhdGFbZmFjdG9yX2NvbHVtbnNdLCBmYWN0b3IpCmBgYAoKIyMgQWx0ZXJuYXRlIERhdGFzZXQgMTogMiUgTUFGLCAyMDB4IGNvdmVyYWdlLCBtaW4uIDEwMCByZWFkcyB0byBjYWxsIG1pbm9yIHZhcmlhbnQKCmBgYHtyfQojbG9hZCBmaWxlIGFuZCB0YWxseSBtaW5vciB2YXJpYW50IHJpY2huZXNzCm1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkPC1yZWFkLmNzdignbWlub3JfdmFyaWFudHNfZmlsdGVyZWRfMjAweDAuMDJfMTAwLmNzdicpIAptY292X3NhbXBsZXNfZmlsdGVyZWQ8LW1jb3Zfc2FtcGxlcyAlPiUgZmlsdGVyKCFydW4gJWluJSBydW5zX3RvX2Ryb3ApICU+JSAKICBmaWx0ZXIocWNfc3RhdHVzPT0icGFzcyIpICU+JSBmaWx0ZXIoIU1Db1ZOdW1iZXIgJWluJSBuZXh0Y2xhZGVfYmFkX3NhbXBsZXMpICU+JSBmaWx0ZXIoc2NvcnBpb19jYWxsIT0iT21pY3JvbiAoQkEuMS1saWtlKSIpICU+JSAKICMjIyMjICNtYWluIGNvdmVyYWdlIGNyaXRlcmlvbiBmb3IgZmFpciBjb21wYXJpc29uczogWCBkZXB0aCBvdmVyIFkgcGVyY2VudCBvZiB0aGUgZ2Vub21lCiAgZmlsdGVyKGZyYWN0aW9uXzIwMHhfY292ZXJhZ2U+PTAuOTgpICU+JSBkcm9wbGV2ZWxzKCkKbl92YXI8LW1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkICU+JSBncm91cF9ieShNQ29WTnVtYmVyKSAlPiUgdGFsbHkoKSAKc2FtcGxlc19uX3ZhcjwtbWNvdl9zYW1wbGVzX2ZpbHRlcmVkICU+JSBsZWZ0X2pvaW4obl92YXIpICU+JSBhcnJhbmdlKENPTExFQ1RJT05fRFQpICU+JSBtdXRhdGUobl92YXI9cmVwbGFjZV9uYShuLCAwKSkKZm9yX3BhdGllbnRfYW5hbHlzaXM8LXNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwyNikgICU+JSBzZWxlY3QoTUNvVk51bWJlciwgbl92YXIsIHNjb3JwaW9fY2FsbCkgCmZvcl9wYXRpZW50X2FuYWx5c2lzICU+JSBwdWxsKG5fdmFyKSAlPiUgc3VtbWFyeQpgYGAKCmBgYHtyfQpmb3JfcGF0aWVudF9hbmFseXNpcyAlPiUgbnJvdygpIAptZWRpYW5fdmFyPC1mb3JfcGF0aWVudF9hbmFseXNpcyAlPiUgcHVsbChuX3ZhcikgJT4lIG1lZGlhbigpCmBgYAoKYGBge3J9CiNhZGQgcGF0aWVudCBtZXRhZGF0YSB0byBzYW1wbGUgbWlub3IgdmFyaWFudCByaWNobmVzcwpwPC1sZWZ0X2pvaW4oZm9yX3BhdGllbnRfYW5hbHlzaXMsIHBhdGllbnRfZGF0YSkgJT4lIGRyb3BsZXZlbHMoKSAlPiUgbXV0YXRlKHZvY0FscGhhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJBbHBoYSIpLDEsMCksIHZvY0RlbHRhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJEZWx0YSIpLDEsMCkpICU+JSBtdXRhdGUodm9jQWxwaGE9YXMuZmFjdG9yKHZvY0FscGhhKSwgdm9jRGVsdGE9YXMuZmFjdG9yKHZvY0RlbHRhKSkKYGBgCgpgYGB7cn0KI1JhbmRvbSBGb3Jlc3QgbW9kZWwgb2YgcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGNsYXNzaWZ5aW5nIGxvdy1DVCBzYW1wbGVzIGFzIGhhdmluZyBoaWdoIG9yIGxvdyBtaW5vciB2YXJpYW50IHJpY2huZXNzCnAgPC0gcCAlPiUgbXV0YXRlKHZhcl9sZXZlbD1pZl9lbHNlKG5fdmFyPD1tZWRpYW5fdmFyLCAibG93IiwiaGlnaCIpKSAlPiUgbXV0YXRlKHZhcl9sZXZlbD1hcy5mYWN0b3IodmFyX2xldmVsKSkgCgpwX3NlbGVjdCA8LSBwICAlPiUgc2VsZWN0KGFnZTE4dW5kZXIsIGFnZTE4dG81NCwgYWdlNTVwbHVzLCBzZXgsIGV0aG5pY2l0eSwgY2hyb25pY19sdW5nX2Rpc2Vhc2UsIGNocm9uaWNfbGl2ZXJfZGlzZWFzZSwgY2hyb25pY19raWRuZXlfZGlzZWFzZSwgY2hyb25pY19oZWFydF9kaXNlYXNlLCBoeXBlcnRlbnNpb24sIGRpYWJldGVzLCBjYW5jZXIsIG9iZXNpdHksIHRyYW5zcGxhbnRfcGF0aWVudCwgcGxhc21hLCBtQWIsIHZhY2NpbmVfc3RhdHVzLCBhZG1pdHRlZF9ob3NwaXRhbCxzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCB2YXJfbGV2ZWwpIAoKcC5yZjwtcmFuZG9tRm9yZXN0KHZhcl9sZXZlbH4uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1wX3NlbGVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudHJlZT0xMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG10cnk9NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUKSAKCmltcG9ydGFuY2UucmFuZG9tRm9yZXN0IDwtIGFzLmRhdGEuZnJhbWUocmFuZG9tRm9yZXN0OjppbXBvcnRhbmNlKHAucmYpKQoKaW1wb3J0YW5jZS5yYW5kb21Gb3Jlc3Q8LWltcG9ydGFuY2UucmFuZG9tRm9yZXN0ICU+JSBhcnJhbmdlKGRlc2MoTWVhbkRlY3JlYXNlQWNjdXJhY3kpKQppbXBvcnRhbmNlLnJhbmRvbUZvcmVzdAoKcmYucm9jPC1yb2MocF9zZWxlY3QkdmFyX2xldmVsLHAucmYkdm90ZXNbLDJdLCBsZXZlbHM9YyhjYXNlPSJoaWdoIixjb250cm9sPSJsb3ciKSkKYXVjKHJmLnJvYykKYGBgCgojIyMgQXNzb2NpYXRpb24gYmV0d2VlbiBwYXRpZW50IGhvc3BpdGFsaXphdGlvbiBhbmQgaGlnaCBtaW5vciB2YXJpYW50IHJpY2huZXNzCgpgYGB7cn0KY2F0ZWdvcmllczwtcCAlPiUgbXV0YXRlKG1pbm9yX2dyZWF0ZXJfMD1pZl9lbHNlKG5fdmFyPjAsJ3llcycsJ25vJykpICU+JSBtdXRhdGUobWlub3JfZ3JlYXRlcl81PWlmX2Vsc2Uobl92YXI+NSwneWVzJywnbm8nKSkgJT4lIG11dGF0ZShtaW5vcl9ncmVhdGVyXzEwPWlmX2Vsc2Uobl92YXI+MTAsJ3llcycsJ25vJykpIApjYXRlZ29yaWVzMTwtY2F0ZWdvcmllcyAlPiUgZ3JvdXBfYnkoYWRtaXR0ZWRfaG9zcGl0YWwsIG1pbm9yX2dyZWF0ZXJfMCkgJT4lIHRhbGx5KCkgJT4lIGdncGxvdChhZXMoeD1hZG1pdHRlZF9ob3NwaXRhbCwgeT1uLCBmaWxsPW1pbm9yX2dyZWF0ZXJfMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCmNhdGVnb3JpZXMyPC1jYXRlZ29yaWVzICU+JSBncm91cF9ieShhZG1pdHRlZF9ob3NwaXRhbCwgbWlub3JfZ3JlYXRlcl81KSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl81KSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImdyYXkiLCJibGFjayIpKSArIHRoZW1lX2J3KCkKY2F0ZWdvcmllczM8LWNhdGVnb3JpZXMgJT4lIGdyb3VwX2J5KGFkbWl0dGVkX2hvc3BpdGFsLCBtaW5vcl9ncmVhdGVyXzEwKSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl8xMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCnBsb3RfZ3JpZChjYXRlZ29yaWVzMSwgY2F0ZWdvcmllczIsIGNhdGVnb3JpZXMzLCBucm93PTMpCmBgYAoKYGBge3J9Cmhvc3BpdGFsaXphdGlvbjwtdGFibGUocCRhZG1pdHRlZF9ob3NwaXRhbCxwJHZhcl9sZXZlbCkgCmhvc3BpdGFsaXphdGlvbgpgYGAKCmBgYHtyfQpjaGlzcS50ZXN0KGhvc3BpdGFsaXphdGlvbikKYGBgCgpgYGB7cn0Kb2Rkc3JhdGlvKGhvc3BpdGFsaXphdGlvbiwgcmV2PSJjb2x1bW5zIikKYGBgCgpgYGB7cn0KI2xpbmVhciBtaXhlZC1lZmZlY3QgbW9kZWwgd2l0aCBzZXF1ZW5jaW5nIHJ1biBhcyByYW5kb20gZWZmZWN0CmxtZShsb2cxMChuX3ZhcisxKSB+IENUKmFkbWl0dGVkX2hvc3BpdGFsLCByYW5kb209fjF8cnVuLAogICAgICAgICAgICBkYXRhPXApICU+JSBhbm92YSgpIApgYGAKCmBgYHtyfQpob3NwX2FsdGRhdGExPC1wICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nMTAobl92YXIrMSksIGNvbG9yPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFya3JlZCIpKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKyB0aGVtZV9idygpICsgYW5ub3RhdGUoInRleHQiLCB4PTEwLCB5PTIsIGxhYmVsPSJDdCBwPDAuMDAwMSBcbmhvc3BpdGFsaXphdGlvbiBwPDAuMDAwMSBcbkN0Kmhvc3BpdGFsaXphdGlvbiBwPDAuMDAwMSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIHlsaW0oMCwyLjYpCmBgYAoKCgojIyMgT3RoZXIgd2F5cyBvZiBleGFtaW5pbmcgZGlzZWFzZSBzZXZlcml0eTogdmFjY2luYXRpb24gc3RhdHVzIGFuZCBoZWFsdGhjYXJlIHdvcmtlciBzdXJ2ZWlsbGFuY2UKCmBgYHtyfQojd2hlbiBkaWQgbW9zdCBjYXNlcyBhbW9uZyB2YWNjaW5hdGVkIHBhdGllbnRzIG9jY3VyPwp0YWJsZShwJGNvbGxlY3Rpb25fbW9udGgsIHAkdmFjY2luZV9zdGF0dXMpCmBgYAoKCmBgYHtyfQp2YXhfc3RhdHVzX3N1YnNldDwtIHNhbXBsZXNfbl92YXIgJT4lIGZpbHRlcihJTlNUUlVNRU5UX1JFU1VMVDwzNSkgICU+JSBzZWxlY3QoTUNvVk51bWJlciwgbl92YXIsIHNjb3JwaW9fY2FsbCkgJT4lIGxlZnRfam9pbihwYXRpZW50X2RhdGEpICU+JSAKICBmaWx0ZXIoY29sbGVjdGlvbl9kYXRlPj0iMjAyMS0wNy0wMSIpICU+JSBmaWx0ZXIoYWRtaXR0ZWRfaG9zcGl0YWw9PTApIApsbWUobG9nMTAobl92YXIrMSkgfiBDVCp2YWNjaW5lX3N0YXR1cywgcmFuZG9tPX4xfHJ1biwKICAgICAgICAgICAgZGF0YT12YXhfc3RhdHVzX3N1YnNldCkgJT4lIGFub3ZhKCkgCgpgYGAKCgpgYGB7cn0KI3RvIHNlZSBlZmZlY3Qgb2YgdmFjY2luYXRpb24gKGFzIGEgY29ycmVsYXRlIG9mIGRpc2Vhc2Ugc2V2ZXJpdHkpOiBsaW1pdCB0byBsYXRlciB0aGFuIEp1bHkgYW5kIG9ubHkgbm9uLWhvc3BpdGFsaXplZCBwYXRpZW50cwp2YXhfYWx0ZGF0YTE8LXZheF9zdGF0dXNfc3Vic2V0ICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nMTAobl92YXIrMSksIGNvbG9yPXZhY2NpbmVfc3RhdHVzKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwibGlnaHRibHVlIikpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSArIHRoZW1lX2J3KCkgKyBhbm5vdGF0ZSgidGV4dCIsIHg9MTQsIHk9MiwgbGFiZWw9IkN0IHA8MC4wMDAxIFxudmFjY2luYXRpb24gcD0wLjAxMTkgXG5DdCp2YWNjaW5hdGlvbiBwPTAuMDU1IikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsgeWxpbSgwLDIuNikKYGBgCgpgYGB7cn0KI2hlYWx0aGNhcmUgd29ya2VyIHN1cnZlaWxsYW5jZSAocHJlc3VtZWQgbW9zdGx5IGFzeW1wdG9tYXRpYykgdnMgbm9uLWhvc3BpdGFsaXplZCBwYXRpZW50cyAocHJlc3VtZWQgbW9zdGx5IHN5bXB0b21hdGljKQpzdXJ2X3N1YnNldCA8LSBzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MzUpICAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIG5fdmFyLCBzY29ycGlvX2NhbGwpICU+JSBsZWZ0X2pvaW4ocGF0aWVudF9kYXRhKSAlPiUKICBmaWx0ZXIoYWRtaXR0ZWRfaG9zcGl0YWw9PTApICU+JSBmaWx0ZXIoIShzdXJ2ZWlsbGFuY2Vfc2FtcGxlPT0xICYgcHVpPT0iUFVJIikpICNleGNsdWRlIEhDVyB3aG8gd2VyZSBwYXRpZW50cwpsbWUobG9nMTAobl92YXIrMSkgfiBDVCpzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCByYW5kb209fjF8cnVuLAogICAgICAgICAgICBkYXRhPXN1cnZfc3Vic2V0KSAlPiUgYW5vdmEoKSAKYGBgCgpgYGB7cn0KaGN3X2FsdGRhdGExPC1zdXJ2X3N1YnNldCAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PWxvZzEwKG5fdmFyKzEpLCBjb2xvcj1zdXJ2ZWlsbGFuY2Vfc2FtcGxlKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFya2dyZWVuIikpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSArIHRoZW1lX2J3KCkgKyBhbm5vdGF0ZSgidGV4dCIsIHg9MTIsIHk9MiwgbGFiZWw9IkN0IHA8MC4wMDAxIFxuSENXIHN1cnZlaWxsYW5jZSBwPTAuMDA3IFxuQ3Qqc3VydmVpbGxhbmNlIHA9MC4wMDc2IikrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKyB5bGltKDAsMi42KQpgYGAKCmBgYHtyfQojTEFTU08gcmVncmVzc2lvbiBtb2RlbCBpbmNsdWRpbmcgYWxsIHNhbXBsZSBhbmQgcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgdG8gZXhwbGFpbiBtaW5vciB2YXJpYW50IHJpY2huZXNzCnBfc3ViPC0gcCAlPiUgbGVmdF9qb2luKG1jb3Zfc2FtcGxlcykgI3RvIGFkZCBpbmZvIGFib3V0IGNvdmVyYWdlCnk8LWxvZzEwKHBfc3ViJG5fdmFyKzEpCng8LWRhdGEubWF0cml4KHBfc3ViWywgYygnYWdlMTh1bmRlcicsJ2FnZTU1cGx1cycsJ3NleCcsJ2Nocm9uaWNfbHVuZ19kaXNlYXNlJywgJ2Nocm9uaWNfbGl2ZXJfZGlzZWFzZScsICdjaHJvbmljX2tpZG5leV9kaXNlYXNlJywgJ2Nocm9uaWNfaGVhcnRfZGlzZWFzZScsICdoeXBlcnRlbnNpb24nLCAnZGlhYmV0ZXMnLCAnY2FuY2VyJywgJ29iZXNpdHknLCAncGxhc21hJywgJ21BYicsICdhZG1pdHRlZF9ob3NwaXRhbCcsJ3ZhY2NpbmVfc3RhdHVzJywndm9jQWxwaGEnLCd2b2NEZWx0YScsJ2NvbGxlY3Rpb25fbW9udGgnLCdzdXJ2ZWlsbGFuY2Vfc2FtcGxlJywnQ1QnLCdtZWRpYW5fY292ZXJhZ2UnLCdydW4nKV0pCgpjdl9tb2RlbCA8LSBjdi5nbG1uZXQoeCwgeSwgYWxwaGEgPSAxLCBuZm9sZHM9MTAwKQpwbG90KGN2X21vZGVsKSAKYmVzdF9tb2RlbCA8LSBnbG1uZXQoeCwgeSwgYWxwaGEgPSAxLCBsYW1iZGEgPSBjdl9tb2RlbCRsYW1iZGEubWluKQpiZXN0X21vZGVsJGRldi5yYXRpbwpgYGAKCmBgYHtyfQpsYXNzbzFfYWx0ZGF0YTE8LWNvZWYoYmVzdF9tb2RlbCkgJT4lIGFzLm1hdHJpeCgpICU+JSBkYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSByZW5hbWUoZmFjdG9yPXJvd25hbWUsIGNvZWZmaWNpZW50PXMwKSAlPiUgZmlsdGVyKGZhY3RvciE9IihJbnRlcmNlcHQpIikgJT4lIGFycmFuZ2UoZGVzYyhjb2VmZmljaWVudCkpICU+JSBnZ3Bsb3QoYWVzKHg9Y29lZmZpY2llbnQsIHk9ZmN0X3Jlb3JkZXIoZmFjdG9yLGNvZWZmaWNpZW50KSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSIjRTJEMjAwIiwgY29sb3I9ImdyYXkiKSArIHRoZW1lX2J3KCkgKyB5bGFiKCJGYWN0b3IiKSArIHhsYWIoIkNvZWZmaWNpZW50IikKYGBgCgpgYGB7cn0KI3NhbWUgbW9kZWwgZXhjbHVkaW5nIGFueSBmYWN0b3JzIHdpdGggYSB0ZW1wb3JhbCBzaWduYWwgKFZPQywgdmFjY2luYXRpb24sIGNvbGxlY3Rpb24gbW9udGgsIHJ1bikKeTI8LWxvZzEwKHBfc3ViJG5fdmFyKzEpCngyPC1kYXRhLm1hdHJpeChwX3N1YlssIGMoJ2FnZTE4dW5kZXInLCdhZ2U1NXBsdXMnLCdzZXgnLCdjaHJvbmljX2x1bmdfZGlzZWFzZScsICdjaHJvbmljX2xpdmVyX2Rpc2Vhc2UnLCAnY2hyb25pY19raWRuZXlfZGlzZWFzZScsICdjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UnLCAnaHlwZXJ0ZW5zaW9uJywgJ2RpYWJldGVzJywgJ2NhbmNlcicsICdvYmVzaXR5JywgJ3BsYXNtYScsICdtQWInLCAnYWRtaXR0ZWRfaG9zcGl0YWwnLCAnc3VydmVpbGxhbmNlX3NhbXBsZScsICdDVCcsICdtZWRpYW5fY292ZXJhZ2UnKV0pCgpjdl9tb2RlbF8yIDwtIGN2LmdsbW5ldCh4MiwgeTIsIGFscGhhID0gMSwgbmZvbGRzPTEwMCkKcGxvdChjdl9tb2RlbF8yKSAKYmVzdF9tb2RlbF8yIDwtIGdsbW5ldCh4MiwgeTIsIGFscGhhID0gMSwgbGFtYmRhID0gY3ZfbW9kZWwkbGFtYmRhLm1pbikKYmVzdF9tb2RlbF8yJGRldi5yYXRpbwpgYGAKCmBgYHtyfQpsYXNzbzJfYWx0ZGF0YTE8LWNvZWYoYmVzdF9tb2RlbF8yKSAlPiUgYXMubWF0cml4KCkgJT4lIGRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIHJlbmFtZShmYWN0b3I9cm93bmFtZSwgY29lZmZpY2llbnQ9czApICU+JSBmaWx0ZXIoZmFjdG9yIT0iKEludGVyY2VwdCkiKSAlPiUgYXJyYW5nZShkZXNjKGNvZWZmaWNpZW50KSkgJT4lIGdncGxvdChhZXMoeD1jb2VmZmljaWVudCwgeT1mY3RfcmVvcmRlcihmYWN0b3IsY29lZmZpY2llbnQpKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9IiNFMkQyMDAiLCBjb2xvcj0iYmxhY2siKSArIHRoZW1lX2J3KCkgKyB5bGFiKCJGYWN0b3IiKSArIHhsYWIoIkNvZWZmaWNpZW50IikKYGBgCgpgYGB7cn0KdGl0bGUgPC0gZ2dkcmF3KCkgKyAKICBkcmF3X2xhYmVsKAogICAgIkFsdGVybmF0ZSBkYXRhc2V0IDEiLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gMCkKCmFsbF9wbG90c19hbHRkYXRhMTwtcGxvdF9ncmlkKHBsb3RfZ3JpZChob3NwX2FsdGRhdGExLCB2YXhfYWx0ZGF0YTEsIGhjd19hbHRkYXRhMSwgbmNvbD0zKSwgcGxvdF9ncmlkKGxhc3NvMV9hbHRkYXRhMSwgbGFzc28yX2FsdGRhdGExLCBuY29sPTIpLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYygyLDEpKQoKYWx0XzE8LXBsb3RfZ3JpZCh0aXRsZSwgYWxsX3Bsb3RzX2FsdGRhdGExLCBucm93PTIsIHJlbF9oZWlnaHRzPWMoMC4xLDEpKQpgYGAKCgojIyBBbHRlcm5hdGUgRGF0YXNldCAyOiAzJSBNQUYsIG1pbiA1MDB4IGNvdmVyYWdlLCBtaW4gMjAgcmVhZHMKCmBgYHtyfQojbG9hZCBmaWxlIGFuZCB0YWxseSBtaW5vciB2YXJpYW50IHJpY2huZXNzCm1pbm9yX3ZhcmlhbnRfc2l0ZXNfdGhyZXNob2xkPC1yZWFkLmNzdignbWlub3JfdmFyaWFudHNfZmlsdGVyZWRfNTAweDAuMDNfMjAuY3N2JykgCm1jb3Zfc2FtcGxlc19maWx0ZXJlZDwtbWNvdl9zYW1wbGVzICU+JSBmaWx0ZXIoIXJ1biAlaW4lIHJ1bnNfdG9fZHJvcCkgJT4lIAogIGZpbHRlcihxY19zdGF0dXM9PSJwYXNzIikgJT4lIGZpbHRlcighTUNvVk51bWJlciAlaW4lIG5leHRjbGFkZV9iYWRfc2FtcGxlcykgJT4lIGZpbHRlcihzY29ycGlvX2NhbGwhPSJPbWljcm9uIChCQS4xLWxpa2UpIikgJT4lIAogIyMjIyMgI21haW4gY292ZXJhZ2UgY3JpdGVyaW9uIGZvciBmYWlyIGNvbXBhcmlzb25zOiBYIGRlcHRoIG92ZXIgWSBwZXJjZW50IG9mIHRoZSBnZW5vbWUKICBmaWx0ZXIoZnJhY3Rpb25fNTAweF9jb3ZlcmFnZT49MC45OCkgJT4lIGRyb3BsZXZlbHMoKQpuX3ZhcjwtbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgJT4lIGdyb3VwX2J5KE1Db1ZOdW1iZXIpICU+JSB0YWxseSgpIApzYW1wbGVzX25fdmFyPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGxlZnRfam9pbihuX3ZhcikgJT4lIGFycmFuZ2UoQ09MTEVDVElPTl9EVCkgJT4lIG11dGF0ZShuX3Zhcj1yZXBsYWNlX25hKG4sIDApKQpmb3JfcGF0aWVudF9hbmFseXNpczwtc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2KSAgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBuX3Zhciwgc2NvcnBpb19jYWxsKSAKZm9yX3BhdGllbnRfYW5hbHlzaXMgJT4lIHB1bGwobl92YXIpICU+JSBzdW1tYXJ5CgpgYGAKCmBgYHtyfQpmb3JfcGF0aWVudF9hbmFseXNpcyAlPiUgbnJvdygpIAptZWRpYW5fdmFyPC1mb3JfcGF0aWVudF9hbmFseXNpcyAlPiUgcHVsbChuX3ZhcikgJT4lIG1lZGlhbigpCmBgYAoKYGBge3J9CiNhZGQgcGF0aWVudCBtZXRhZGF0YSB0byBzYW1wbGUgbWlub3IgdmFyaWFudCByaWNobmVzcwpwPC1sZWZ0X2pvaW4oZm9yX3BhdGllbnRfYW5hbHlzaXMsIHBhdGllbnRfZGF0YSkgJT4lIGRyb3BsZXZlbHMoKSAlPiUgbXV0YXRlKHZvY0FscGhhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJBbHBoYSIpLDEsMCksIHZvY0RlbHRhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJEZWx0YSIpLDEsMCkpICU+JSBtdXRhdGUodm9jQWxwaGE9YXMuZmFjdG9yKHZvY0FscGhhKSwgdm9jRGVsdGE9YXMuZmFjdG9yKHZvY0RlbHRhKSkKYGBgCgpgYGB7cn0KI1JhbmRvbSBGb3Jlc3QgbW9kZWwgb2YgcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGNsYXNzaWZ5aW5nIGxvdy1DVCBzYW1wbGVzIGFzIGhhdmluZyBoaWdoIG9yIGxvdyBtaW5vciB2YXJpYW50IHJpY2huZXNzCnAgPC0gcCAlPiUgbXV0YXRlKHZhcl9sZXZlbD1pZl9lbHNlKG5fdmFyPD1tZWRpYW5fdmFyLCAibG93IiwiaGlnaCIpKSAlPiUgbXV0YXRlKHZhcl9sZXZlbD1hcy5mYWN0b3IodmFyX2xldmVsKSkgCgpwX3NlbGVjdCA8LSBwICAlPiUgc2VsZWN0KGFnZTE4dW5kZXIsIGFnZTE4dG81NCwgYWdlNTVwbHVzLCBzZXgsIGV0aG5pY2l0eSwgY2hyb25pY19sdW5nX2Rpc2Vhc2UsIGNocm9uaWNfbGl2ZXJfZGlzZWFzZSwgY2hyb25pY19raWRuZXlfZGlzZWFzZSwgY2hyb25pY19oZWFydF9kaXNlYXNlLCBoeXBlcnRlbnNpb24sIGRpYWJldGVzLCBjYW5jZXIsIG9iZXNpdHksIHRyYW5zcGxhbnRfcGF0aWVudCwgcGxhc21hLCBtQWIsIHZhY2NpbmVfc3RhdHVzLCBhZG1pdHRlZF9ob3NwaXRhbCxzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCB2YXJfbGV2ZWwpIAoKcC5yZjwtcmFuZG9tRm9yZXN0KHZhcl9sZXZlbH4uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1wX3NlbGVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudHJlZT0xMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG10cnk9NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUKSAKCmltcG9ydGFuY2UucmFuZG9tRm9yZXN0IDwtIGFzLmRhdGEuZnJhbWUocmFuZG9tRm9yZXN0OjppbXBvcnRhbmNlKHAucmYpKQoKaW1wb3J0YW5jZS5yYW5kb21Gb3Jlc3Q8LWltcG9ydGFuY2UucmFuZG9tRm9yZXN0ICU+JSBhcnJhbmdlKGRlc2MoTWVhbkRlY3JlYXNlQWNjdXJhY3kpKQppbXBvcnRhbmNlLnJhbmRvbUZvcmVzdAoKcmYucm9jPC1yb2MocF9zZWxlY3QkdmFyX2xldmVsLHAucmYkdm90ZXNbLDJdLCBsZXZlbHM9YyhjYXNlPSJoaWdoIixjb250cm9sPSJsb3ciKSkKYXVjKHJmLnJvYykKYGBgCgojIyMgQXNzb2NpYXRpb24gYmV0d2VlbiBwYXRpZW50IGhvc3BpdGFsaXphdGlvbiBhbmQgaGlnaCBtaW5vciB2YXJpYW50IHJpY2huZXNzCgpgYGB7cn0KY2F0ZWdvcmllczwtcCAlPiUgbXV0YXRlKG1pbm9yX2dyZWF0ZXJfMD1pZl9lbHNlKG5fdmFyPjAsJ3llcycsJ25vJykpICU+JSBtdXRhdGUobWlub3JfZ3JlYXRlcl81PWlmX2Vsc2Uobl92YXI+NSwneWVzJywnbm8nKSkgJT4lIG11dGF0ZShtaW5vcl9ncmVhdGVyXzEwPWlmX2Vsc2Uobl92YXI+MTAsJ3llcycsJ25vJykpIApjYXRlZ29yaWVzMTwtY2F0ZWdvcmllcyAlPiUgZ3JvdXBfYnkoYWRtaXR0ZWRfaG9zcGl0YWwsIG1pbm9yX2dyZWF0ZXJfMCkgJT4lIHRhbGx5KCkgJT4lIGdncGxvdChhZXMoeD1hZG1pdHRlZF9ob3NwaXRhbCwgeT1uLCBmaWxsPW1pbm9yX2dyZWF0ZXJfMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCmNhdGVnb3JpZXMyPC1jYXRlZ29yaWVzICU+JSBncm91cF9ieShhZG1pdHRlZF9ob3NwaXRhbCwgbWlub3JfZ3JlYXRlcl81KSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl81KSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImdyYXkiLCJibGFjayIpKSArIHRoZW1lX2J3KCkKY2F0ZWdvcmllczM8LWNhdGVnb3JpZXMgJT4lIGdyb3VwX2J5KGFkbWl0dGVkX2hvc3BpdGFsLCBtaW5vcl9ncmVhdGVyXzEwKSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl8xMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCnBsb3RfZ3JpZChjYXRlZ29yaWVzMSwgY2F0ZWdvcmllczIsIGNhdGVnb3JpZXMzLCBucm93PTMpCmBgYAoKYGBge3J9Cmhvc3BpdGFsaXphdGlvbjwtdGFibGUocCRhZG1pdHRlZF9ob3NwaXRhbCxwJHZhcl9sZXZlbCkgCmhvc3BpdGFsaXphdGlvbgpgYGAKCmBgYHtyfQpjaGlzcS50ZXN0KGhvc3BpdGFsaXphdGlvbikKYGBgCgpgYGB7cn0Kb2Rkc3JhdGlvKGhvc3BpdGFsaXphdGlvbiwgcmV2PSJjb2x1bW5zIikKYGBgCgpgYGB7cn0KI2xpbmVhciBtaXhlZC1lZmZlY3QgbW9kZWwgd2l0aCBzZXF1ZW5jaW5nIHJ1biBhcyByYW5kb20gZWZmZWN0CmxtZShsb2cxMChuX3ZhcisxKSB+IENUKmFkbWl0dGVkX2hvc3BpdGFsLCByYW5kb209fjF8cnVuLAogICAgICAgICAgICBkYXRhPXApICU+JSBhbm92YSgpIApgYGAKCmBgYHtyfQpob3NwX2FsdGRhdGEyPC1wICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nMTAobl92YXIrMSksIGNvbG9yPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFya3JlZCIpKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKyB0aGVtZV9idygpICsgYW5ub3RhdGUoInRleHQiLCB4PTEwLCB5PTEuNzUsIGxhYmVsPSJDdCBwPDAuMDAwMSBcbmhvc3BpdGFsaXphdGlvbiBwPDAuMDAwMSBcbkN0Kmhvc3BpdGFsaXphdGlvbiBwPTAuMDA1OSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIHlsaW0oMCwyLjYpCmhvc3BfYWx0ZGF0YTIKYGBgCgpgYGB7cn0KdmF4X3N0YXR1c19zdWJzZXQ8LSBzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MzUpICAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIG5fdmFyLCBzY29ycGlvX2NhbGwpICU+JSBsZWZ0X2pvaW4ocGF0aWVudF9kYXRhKSAlPiUgCiAgZmlsdGVyKGNvbGxlY3Rpb25fZGF0ZT49IjIwMjEtMDctMDEiKSAlPiUgZmlsdGVyKGFkbWl0dGVkX2hvc3BpdGFsPT0wKSAKbG1lKGxvZzEwKG5fdmFyKzEpIH4gQ1QqdmFjY2luZV9zdGF0dXMsIHJhbmRvbT1+MXxydW4sCiAgICAgICAgICAgIGRhdGE9dmF4X3N0YXR1c19zdWJzZXQpICU+JSBhbm92YSgpIApgYGAKCmBgYHtyfQojdG8gc2VlIGVmZmVjdCBvZiB2YWNjaW5hdGlvbiAoYXMgYSBjb3JyZWxhdGUgb2YgZGlzZWFzZSBzZXZlcml0eSk6IGxpbWl0IHRvIGxhdGVyIHRoYW4gSnVseSBhbmQgb25seSBub24taG9zcGl0YWxpemVkIHBhdGllbnRzCnZheF9hbHRkYXRhMjwtdmF4X3N0YXR1c19zdWJzZXQgJT4lIGdncGxvdChhZXMoeD1DVCwgeT1sb2cxMChuX3ZhcisxKSwgY29sb3I9dmFjY2luZV9zdGF0dXMpKSArIGdlb21fcG9pbnQoYWxwaGE9MC41KSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCJsaWdodGJsdWUiKSkgKyBnZW9tX3Ntb290aChtZXRob2Q9bG0pICsgdGhlbWVfYncoKSArIGFubm90YXRlKCJ0ZXh0IiwgeD0xNCwgeT0xLjc1LCBsYWJlbD0iQ3QgcDwwLjAwMDEgXG52YWNjaW5hdGlvbiBwPTAuMDY3MSBcbkN0KnZhY2NpbmF0aW9uIHA9MC4wMjI2IikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsgeWxpbSgwLDIuNikKdmF4X2FsdGRhdGEyCmBgYAoKYGBge3J9CiNoZWFsdGhjYXJlIHdvcmtlciBzdXJ2ZWlsbGFuY2UgKHByZXN1bWVkIG1vc3RseSBhc3ltcHRvbWF0aWMpIHZzIG5vbi1ob3NwaXRhbGl6ZWQgcGF0aWVudHMgKHByZXN1bWVkIG1vc3RseSBzeW1wdG9tYXRpYykKc3Vydl9zdWJzZXQgPC0gc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDM1KSAgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBuX3Zhciwgc2NvcnBpb19jYWxsKSAlPiUgbGVmdF9qb2luKHBhdGllbnRfZGF0YSkgJT4lCiAgZmlsdGVyKGFkbWl0dGVkX2hvc3BpdGFsPT0wKSAlPiUgZmlsdGVyKCEoc3VydmVpbGxhbmNlX3NhbXBsZT09MSAmIHB1aT09IlBVSSIpKSAjZXhjbHVkZSBIQ1cgd2hvIHdlcmUgcGF0aWVudHMKbG1lKGxvZzEwKG5fdmFyKzEpIH4gQ1Qqc3VydmVpbGxhbmNlX3NhbXBsZSwgcmFuZG9tPX4xfHJ1biwKICAgICAgICAgICAgZGF0YT1zdXJ2X3N1YnNldCkgJT4lIGFub3ZhKCkgCmBgYAoKYGBge3J9Cmhjd19hbHRkYXRhMjwtc3Vydl9zdWJzZXQgJT4lIGdncGxvdChhZXMoeD1DVCwgeT1sb2cxMChuX3ZhcisxKSwgY29sb3I9c3VydmVpbGxhbmNlX3NhbXBsZSkpICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsImRhcmtncmVlbiIpKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKyB0aGVtZV9idygpICsgYW5ub3RhdGUoInRleHQiLCB4PTEyLCB5PTEuNzUsIGxhYmVsPSJDdCBwPDAuMDAwMSBcbkhDVyBzdXJ2ZWlsbGFuY2UgcD0wLjAwNzcgXG5DdCpzdXJ2ZWlsbGFuY2UgcD0wLjAwMDEiKSsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIHlsaW0oMCwyLjYpCmhjd19hbHRkYXRhMgpgYGAKCmBgYHtyfQojTEFTU08gcmVncmVzc2lvbiBtb2RlbCBpbmNsdWRpbmcgYWxsIHNhbXBsZSBhbmQgcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgdG8gZXhwbGFpbiBtaW5vciB2YXJpYW50IHJpY2huZXNzCnBfc3ViPC0gcCAlPiUgbGVmdF9qb2luKG1jb3Zfc2FtcGxlcykgI3RvIGFkZCBpbmZvIGFib3V0IGNvdmVyYWdlCnk8LWxvZzEwKHBfc3ViJG5fdmFyKzEpCng8LWRhdGEubWF0cml4KHBfc3ViWywgYygnYWdlMTh1bmRlcicsJ2FnZTU1cGx1cycsJ3NleCcsJ2Nocm9uaWNfbHVuZ19kaXNlYXNlJywgJ2Nocm9uaWNfbGl2ZXJfZGlzZWFzZScsICdjaHJvbmljX2tpZG5leV9kaXNlYXNlJywgJ2Nocm9uaWNfaGVhcnRfZGlzZWFzZScsICdoeXBlcnRlbnNpb24nLCAnZGlhYmV0ZXMnLCAnY2FuY2VyJywgJ29iZXNpdHknLCAncGxhc21hJywgJ21BYicsICdhZG1pdHRlZF9ob3NwaXRhbCcsJ3ZhY2NpbmVfc3RhdHVzJywndm9jQWxwaGEnLCd2b2NEZWx0YScsJ2NvbGxlY3Rpb25fbW9udGgnLCdzdXJ2ZWlsbGFuY2Vfc2FtcGxlJywnQ1QnLCdtZWRpYW5fY292ZXJhZ2UnLCdydW4nKV0pCgpjdl9tb2RlbCA8LSBjdi5nbG1uZXQoeCwgeSwgYWxwaGEgPSAxLCBuZm9sZHM9MTAwKQpwbG90KGN2X21vZGVsKSAKYmVzdF9tb2RlbCA8LSBnbG1uZXQoeCwgeSwgYWxwaGEgPSAxLCBsYW1iZGEgPSBjdl9tb2RlbCRsYW1iZGEubWluKQpiZXN0X21vZGVsJGRldi5yYXRpbwpgYGAKCmBgYHtyfQpsYXNzbzFfYWx0ZGF0YTI8LWNvZWYoYmVzdF9tb2RlbCkgJT4lIGFzLm1hdHJpeCgpICU+JSBkYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSByZW5hbWUoZmFjdG9yPXJvd25hbWUsIGNvZWZmaWNpZW50PXMwKSAlPiUgZmlsdGVyKGZhY3RvciE9IihJbnRlcmNlcHQpIikgJT4lIGFycmFuZ2UoZGVzYyhjb2VmZmljaWVudCkpICU+JSBnZ3Bsb3QoYWVzKHg9Y29lZmZpY2llbnQsIHk9ZmN0X3Jlb3JkZXIoZmFjdG9yLGNvZWZmaWNpZW50KSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSIjRTJEMjAwIiwgY29sb3I9ImdyYXkiKSArIHRoZW1lX2J3KCkgKyB5bGFiKCJGYWN0b3IiKSArIHhsYWIoIkNvZWZmaWNpZW50IikKYGBgCgpgYGB7cn0KI3NhbWUgbW9kZWwgZXhjbHVkaW5nIGFueSBmYWN0b3JzIHdpdGggYSB0ZW1wb3JhbCBzaWduYWwgKFZPQywgdmFjY2luYXRpb24sIGNvbGxlY3Rpb24gbW9udGgsIHJ1bikKeTI8LWxvZzEwKHBfc3ViJG5fdmFyKzEpCngyPC1kYXRhLm1hdHJpeChwX3N1YlssIGMoJ2FnZTE4dW5kZXInLCdhZ2U1NXBsdXMnLCdzZXgnLCdjaHJvbmljX2x1bmdfZGlzZWFzZScsICdjaHJvbmljX2xpdmVyX2Rpc2Vhc2UnLCAnY2hyb25pY19raWRuZXlfZGlzZWFzZScsICdjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UnLCAnaHlwZXJ0ZW5zaW9uJywgJ2RpYWJldGVzJywgJ2NhbmNlcicsICdvYmVzaXR5JywgJ3BsYXNtYScsICdtQWInLCAnYWRtaXR0ZWRfaG9zcGl0YWwnLCAnc3VydmVpbGxhbmNlX3NhbXBsZScsICdDVCcsICdtZWRpYW5fY292ZXJhZ2UnKV0pCgpjdl9tb2RlbF8yIDwtIGN2LmdsbW5ldCh4MiwgeTIsIGFscGhhID0gMSwgbmZvbGRzPTEwMCkKcGxvdChjdl9tb2RlbF8yKSAKYmVzdF9tb2RlbF8yIDwtIGdsbW5ldCh4MiwgeTIsIGFscGhhID0gMSwgbGFtYmRhID0gY3ZfbW9kZWwkbGFtYmRhLm1pbikKYmVzdF9tb2RlbF8yJGRldi5yYXRpbwpgYGAKCmBgYHtyfQpsYXNzbzJfYWx0ZGF0YTI8LWNvZWYoYmVzdF9tb2RlbF8yKSAlPiUgYXMubWF0cml4KCkgJT4lIGRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIHJlbmFtZShmYWN0b3I9cm93bmFtZSwgY29lZmZpY2llbnQ9czApICU+JSBmaWx0ZXIoZmFjdG9yIT0iKEludGVyY2VwdCkiKSAlPiUgYXJyYW5nZShkZXNjKGNvZWZmaWNpZW50KSkgJT4lIGdncGxvdChhZXMoeD1jb2VmZmljaWVudCwgeT1mY3RfcmVvcmRlcihmYWN0b3IsY29lZmZpY2llbnQpKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9IiNFMkQyMDAiLCBjb2xvcj0iYmxhY2siKSArIHRoZW1lX2J3KCkgKyB5bGFiKCJGYWN0b3IiKSArIHhsYWIoIkNvZWZmaWNpZW50IikKYGBgCgpgYGB7cn0KdGl0bGUgPC0gZ2dkcmF3KCkgKyAKICBkcmF3X2xhYmVsKAogICAgIkFsdGVybmF0ZSBkYXRhc2V0IDIiLAogICAgZm9udGZhY2UgPSAnYm9sZCcsCiAgICB4ID0gMCwKICAgIGhqdXN0ID0gMCkKCmFsbF9wbG90c19hbHRkYXRhMjwtcGxvdF9ncmlkKHBsb3RfZ3JpZChob3NwX2FsdGRhdGEyLCB2YXhfYWx0ZGF0YTIsIGhjd19hbHRkYXRhMiwgbmNvbD0zKSwgcGxvdF9ncmlkKGxhc3NvMV9hbHRkYXRhMiwgbGFzc28yX2FsdGRhdGEyLCBuY29sPTIpLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYygyLDEpKQoKYWx0XzI8LXBsb3RfZ3JpZCh0aXRsZSwgYWxsX3Bsb3RzX2FsdGRhdGEyLCBucm93PTIsIHJlbF9oZWlnaHRzPWMoMC4xLDEpKQphbHRfMgpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgojIyBBbHRlcm5hdGUgRGF0YXNldCAzOiBNQUYgMSUsIG1pbmltdW0gMTAwMHggY292ZXJhZ2UgCgpgYGB7cn0KI2xvYWQgZmlsZSBhbmQgdGFsbHkgbWlub3IgdmFyaWFudCByaWNobmVzcwptaW5vcl92YXJpYW50X3NpdGVzX3RocmVzaG9sZDwtcmVhZC5jc3YoJ21pbm9yX3ZhcmlhbnRzX2ZpbHRlcmVkXzEwMDB4MC4wMS5jc3YnKSAKbWNvdl9zYW1wbGVzX2ZpbHRlcmVkPC1tY292X3NhbXBsZXMgJT4lIGZpbHRlcighcnVuICVpbiUgcnVuc190b19kcm9wKSAlPiUgCiAgZmlsdGVyKHFjX3N0YXR1cz09InBhc3MiKSAlPiUgZmlsdGVyKCFNQ29WTnVtYmVyICVpbiUgbmV4dGNsYWRlX2JhZF9zYW1wbGVzKSAlPiUgZmlsdGVyKHNjb3JwaW9fY2FsbCE9Ik9taWNyb24gKEJBLjEtbGlrZSkiKSAlPiUgCiAjIyMjIyAjbWFpbiBjb3ZlcmFnZSBjcml0ZXJpb24gZm9yIGZhaXIgY29tcGFyaXNvbnM6IFggZGVwdGggb3ZlciBZIHBlcmNlbnQgb2YgdGhlIGdlbm9tZQogIGZpbHRlcihmcmFjdGlvbl8xMDAweF9jb3ZlcmFnZT49MC45OCkgJT4lIGRyb3BsZXZlbHMoKQpuX3ZhcjwtbWlub3JfdmFyaWFudF9zaXRlc190aHJlc2hvbGQgJT4lIGdyb3VwX2J5KE1Db1ZOdW1iZXIpICU+JSB0YWxseSgpIApzYW1wbGVzX25fdmFyPC1tY292X3NhbXBsZXNfZmlsdGVyZWQgJT4lIGxlZnRfam9pbihuX3ZhcikgJT4lIGFycmFuZ2UoQ09MTEVDVElPTl9EVCkgJT4lIG11dGF0ZShuX3Zhcj1yZXBsYWNlX25hKG4sIDApKQpmb3JfcGF0aWVudF9hbmFseXNpczwtc2FtcGxlc19uX3ZhciAlPiUgZmlsdGVyKElOU1RSVU1FTlRfUkVTVUxUPDI2KSAgJT4lIHNlbGVjdChNQ29WTnVtYmVyLCBuX3Zhciwgc2NvcnBpb19jYWxsKSAKZm9yX3BhdGllbnRfYW5hbHlzaXMgJT4lIHB1bGwobl92YXIpICU+JSBzdW1tYXJ5CmBgYAoKYGBge3J9CmZvcl9wYXRpZW50X2FuYWx5c2lzICU+JSBucm93KCkgCm1lZGlhbl92YXI8LWZvcl9wYXRpZW50X2FuYWx5c2lzICU+JSBwdWxsKG5fdmFyKSAlPiUgbWVkaWFuKCkKYGBgCgoKYGBge3J9CiNhZGQgcGF0aWVudCBtZXRhZGF0YSB0byBzYW1wbGUgbWlub3IgdmFyaWFudCByaWNobmVzcwpwPC1sZWZ0X2pvaW4oZm9yX3BhdGllbnRfYW5hbHlzaXMsIHBhdGllbnRfZGF0YSkgJT4lIGRyb3BsZXZlbHMoKSAlPiUgbXV0YXRlKHZvY0FscGhhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJBbHBoYSIpLDEsMCksIHZvY0RlbHRhPWlmX2Vsc2Uoc3RhcnRzV2l0aChzY29ycGlvX2NhbGwsICJEZWx0YSIpLDEsMCkpICU+JSBtdXRhdGUodm9jQWxwaGE9YXMuZmFjdG9yKHZvY0FscGhhKSwgdm9jRGVsdGE9YXMuZmFjdG9yKHZvY0RlbHRhKSkKYGBgCgpgYGB7cn0KI1JhbmRvbSBGb3Jlc3QgbW9kZWwgb2YgcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGNsYXNzaWZ5aW5nIGxvdy1DVCBzYW1wbGVzIGFzIGhhdmluZyBoaWdoIG9yIGxvdyBtaW5vciB2YXJpYW50IHJpY2huZXNzCnAgPC0gcCAlPiUgbXV0YXRlKHZhcl9sZXZlbD1pZl9lbHNlKG5fdmFyPD1tZWRpYW5fdmFyLCAibG93IiwiaGlnaCIpKSAlPiUgbXV0YXRlKHZhcl9sZXZlbD1hcy5mYWN0b3IodmFyX2xldmVsKSkgCgpwX3NlbGVjdCA8LSBwICAlPiUgc2VsZWN0KGFnZTE4dW5kZXIsIGFnZTE4dG81NCwgYWdlNTVwbHVzLCBzZXgsIGV0aG5pY2l0eSwgY2hyb25pY19sdW5nX2Rpc2Vhc2UsIGNocm9uaWNfbGl2ZXJfZGlzZWFzZSwgY2hyb25pY19raWRuZXlfZGlzZWFzZSwgY2hyb25pY19oZWFydF9kaXNlYXNlLCBoeXBlcnRlbnNpb24sIGRpYWJldGVzLCBjYW5jZXIsIG9iZXNpdHksIHRyYW5zcGxhbnRfcGF0aWVudCwgcGxhc21hLCBtQWIsIHZhY2NpbmVfc3RhdHVzLCBhZG1pdHRlZF9ob3NwaXRhbCxzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCB2YXJfbGV2ZWwpIAoKcC5yZjwtcmFuZG9tRm9yZXN0KHZhcl9sZXZlbH4uLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT1wX3NlbGVjdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBudHJlZT0xMDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG10cnk9NSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcG9ydGFuY2UgPSBUKSAKCmltcG9ydGFuY2UucmFuZG9tRm9yZXN0IDwtIGFzLmRhdGEuZnJhbWUocmFuZG9tRm9yZXN0OjppbXBvcnRhbmNlKHAucmYpKQoKaW1wb3J0YW5jZS5yYW5kb21Gb3Jlc3Q8LWltcG9ydGFuY2UucmFuZG9tRm9yZXN0ICU+JSBhcnJhbmdlKGRlc2MoTWVhbkRlY3JlYXNlQWNjdXJhY3kpKQppbXBvcnRhbmNlLnJhbmRvbUZvcmVzdAoKcmYucm9jPC1yb2MocF9zZWxlY3QkdmFyX2xldmVsLHAucmYkdm90ZXNbLDJdLCBsZXZlbHM9YyhjYXNlPSJoaWdoIixjb250cm9sPSJsb3ciKSkKYXVjKHJmLnJvYykKYGBgCgojIyMgQXNzb2NpYXRpb24gYmV0d2VlbiBwYXRpZW50IGhvc3BpdGFsaXphdGlvbiBhbmQgaGlnaCBtaW5vciB2YXJpYW50IHJpY2huZXNzCgpgYGB7cn0KY2F0ZWdvcmllczwtcCAlPiUgbXV0YXRlKG1pbm9yX2dyZWF0ZXJfMD1pZl9lbHNlKG5fdmFyPjAsJ3llcycsJ25vJykpICU+JSBtdXRhdGUobWlub3JfZ3JlYXRlcl81PWlmX2Vsc2Uobl92YXI+NSwneWVzJywnbm8nKSkgJT4lIG11dGF0ZShtaW5vcl9ncmVhdGVyXzEwPWlmX2Vsc2Uobl92YXI+MTAsJ3llcycsJ25vJykpIApjYXRlZ29yaWVzMTwtY2F0ZWdvcmllcyAlPiUgZ3JvdXBfYnkoYWRtaXR0ZWRfaG9zcGl0YWwsIG1pbm9yX2dyZWF0ZXJfMCkgJT4lIHRhbGx5KCkgJT4lIGdncGxvdChhZXMoeD1hZG1pdHRlZF9ob3NwaXRhbCwgeT1uLCBmaWxsPW1pbm9yX2dyZWF0ZXJfMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCmNhdGVnb3JpZXMyPC1jYXRlZ29yaWVzICU+JSBncm91cF9ieShhZG1pdHRlZF9ob3NwaXRhbCwgbWlub3JfZ3JlYXRlcl81KSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl81KSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImdyYXkiLCJibGFjayIpKSArIHRoZW1lX2J3KCkKY2F0ZWdvcmllczM8LWNhdGVnb3JpZXMgJT4lIGdyb3VwX2J5KGFkbWl0dGVkX2hvc3BpdGFsLCBtaW5vcl9ncmVhdGVyXzEwKSAlPiUgdGFsbHkoKSAlPiUgZ2dwbG90KGFlcyh4PWFkbWl0dGVkX2hvc3BpdGFsLCB5PW4sIGZpbGw9bWlub3JfZ3JlYXRlcl8xMCkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCJncmF5IiwiYmxhY2siKSkgKyB0aGVtZV9idygpCnBsb3RfZ3JpZChjYXRlZ29yaWVzMSwgY2F0ZWdvcmllczIsIGNhdGVnb3JpZXMzLCBucm93PTMpCmBgYAoKYGBge3J9Cmhvc3BpdGFsaXphdGlvbjwtdGFibGUocCRhZG1pdHRlZF9ob3NwaXRhbCxwJHZhcl9sZXZlbCkgCmhvc3BpdGFsaXphdGlvbgpgYGAKCmBgYHtyfQpjaGlzcS50ZXN0KGhvc3BpdGFsaXphdGlvbikKYGBgCgpgYGB7cn0Kb2Rkc3JhdGlvKGhvc3BpdGFsaXphdGlvbiwgcmV2PSJjb2x1bW5zIikKYGBgCgpgYGB7cn0KI2xpbmVhciBtaXhlZC1lZmZlY3QgbW9kZWwgd2l0aCBzZXF1ZW5jaW5nIHJ1biBhcyByYW5kb20gZWZmZWN0CmxtZShsb2cxMChuX3ZhcisxKSB+IENUKmFkbWl0dGVkX2hvc3BpdGFsLCByYW5kb209fjF8cnVuLAogICAgICAgICAgICBkYXRhPXApICU+JSBhbm92YSgpIApgYGAKCmBgYHtyfQpob3NwX2FsdGRhdGEzPC1wICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nMTAobl92YXIrMSksIGNvbG9yPWFkbWl0dGVkX2hvc3BpdGFsKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFya3JlZCIpKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSkgKyB0aGVtZV9idygpICsgYW5ub3RhdGUoInRleHQiLCB4PTEwLCB5PTIsIGxhYmVsPSJDdCBwPDAuMDAwMSBcbmhvc3BpdGFsaXphdGlvbiBwPDAuMDAwMSBcbkN0Kmhvc3BpdGFsaXphdGlvbiBwPDAuMDAwMSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIHlsaW0oMCwyLjYpCmhvc3BfYWx0ZGF0YTMKYGBgCgpgYGB7cn0KdmF4X3N0YXR1c19zdWJzZXQ8LSBzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MzUpICAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIG5fdmFyLCBzY29ycGlvX2NhbGwpICU+JSBsZWZ0X2pvaW4ocGF0aWVudF9kYXRhKSAlPiUgCiAgZmlsdGVyKGNvbGxlY3Rpb25fZGF0ZT49IjIwMjEtMDctMDEiKSAlPiUgZmlsdGVyKGFkbWl0dGVkX2hvc3BpdGFsPT0wKSAKbG1lKGxvZzEwKG5fdmFyKzEpIH4gQ1QqdmFjY2luZV9zdGF0dXMsIHJhbmRvbT1+MXxydW4sCiAgICAgICAgICAgIGRhdGE9dmF4X3N0YXR1c19zdWJzZXQpICU+JSBhbm92YSgpIAoKYGBgCgpgYGB7cn0KI3RvIHNlZSBlZmZlY3Qgb2YgdmFjY2luYXRpb24gKGFzIGEgY29ycmVsYXRlIG9mIGRpc2Vhc2Ugc2V2ZXJpdHkpOiBsaW1pdCB0byBsYXRlciB0aGFuIEp1bHkgYW5kIG9ubHkgbm9uLWhvc3BpdGFsaXplZCBwYXRpZW50cwp2YXhfYWx0ZGF0YTM8LXZheF9zdGF0dXNfc3Vic2V0ICU+JSBnZ3Bsb3QoYWVzKHg9Q1QsIHk9bG9nMTAobl92YXIrMSksIGNvbG9yPXZhY2NpbmVfc3RhdHVzKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwibGlnaHRibHVlIikpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSArIHRoZW1lX2J3KCkgKyBhbm5vdGF0ZSgidGV4dCIsIHg9MTQsIHk9MiwgbGFiZWw9IkN0IHA8MC4wMDAxIFxudmFjY2luYXRpb24gcD0wLjEwOTggXG5DdCp2YWNjaW5hdGlvbiBwPTAuNTYiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKyB5bGltKDAsMi42KQp2YXhfYWx0ZGF0YTMKYGBgCgpgYGB7cn0KI2hlYWx0aGNhcmUgd29ya2VyIHN1cnZlaWxsYW5jZSAocHJlc3VtZWQgbW9zdGx5IGFzeW1wdG9tYXRpYykgdnMgbm9uLWhvc3BpdGFsaXplZCBwYXRpZW50cyAocHJlc3VtZWQgbW9zdGx5IHN5bXB0b21hdGljKQpzdXJ2X3N1YnNldCA8LSBzYW1wbGVzX25fdmFyICU+JSBmaWx0ZXIoSU5TVFJVTUVOVF9SRVNVTFQ8MzUpICAlPiUgc2VsZWN0KE1Db1ZOdW1iZXIsIG5fdmFyLCBzY29ycGlvX2NhbGwpICU+JSBsZWZ0X2pvaW4ocGF0aWVudF9kYXRhKSAlPiUKICBmaWx0ZXIoYWRtaXR0ZWRfaG9zcGl0YWw9PTApICU+JSBmaWx0ZXIoIShzdXJ2ZWlsbGFuY2Vfc2FtcGxlPT0xICYgcHVpPT0iUFVJIikpICNleGNsdWRlIEhDVyB3aG8gd2VyZSBwYXRpZW50cwpsbWUobG9nMTAobl92YXIrMSkgfiBDVCpzdXJ2ZWlsbGFuY2Vfc2FtcGxlLCByYW5kb209fjF8cnVuLAogICAgICAgICAgICBkYXRhPXN1cnZfc3Vic2V0KSAlPiUgYW5vdmEoKSAKYGBgCgpgYGB7cn0KaGN3X2FsdGRhdGEzPC1zdXJ2X3N1YnNldCAlPiUgZ2dwbG90KGFlcyh4PUNULCB5PWxvZzEwKG5fdmFyKzEpLCBjb2xvcj1zdXJ2ZWlsbGFuY2Vfc2FtcGxlKSkgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsYWNrIiwiZGFya2dyZWVuIikpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKSArIHRoZW1lX2J3KCkgKyBhbm5vdGF0ZSgidGV4dCIsIHg9MTIsIHk9MiwgbGFiZWw9IkN0IHA8MC4wMDAxIFxuSENXIHN1cnZlaWxsYW5jZSBwPTAuNDQ5IFxuQ3Qqc3VydmVpbGxhbmNlIHA9MC4wMDE5IikrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKyB5bGltKDAsMi42KQpoY3dfYWx0ZGF0YTMKYGBgCgpgYGB7cn0KI0xBU1NPIHJlZ3Jlc3Npb24gbW9kZWwgaW5jbHVkaW5nIGFsbCBzYW1wbGUgYW5kIHBhdGllbnQgY2hhcmFjdGVyaXN0aWNzIHRvIGV4cGxhaW4gbWlub3IgdmFyaWFudCByaWNobmVzcwpwX3N1YjwtIHAgJT4lIGxlZnRfam9pbihtY292X3NhbXBsZXMpICN0byBhZGQgaW5mbyBhYm91dCBjb3ZlcmFnZQp5PC1sb2cxMChwX3N1YiRuX3ZhcisxKQp4PC1kYXRhLm1hdHJpeChwX3N1YlssIGMoJ2FnZTE4dW5kZXInLCdhZ2U1NXBsdXMnLCdzZXgnLCdjaHJvbmljX2x1bmdfZGlzZWFzZScsICdjaHJvbmljX2xpdmVyX2Rpc2Vhc2UnLCAnY2hyb25pY19raWRuZXlfZGlzZWFzZScsICdjaHJvbmljX2hlYXJ0X2Rpc2Vhc2UnLCAnaHlwZXJ0ZW5zaW9uJywgJ2RpYWJldGVzJywgJ2NhbmNlcicsICdvYmVzaXR5JywgJ3BsYXNtYScsICdtQWInLCAnYWRtaXR0ZWRfaG9zcGl0YWwnLCd2YWNjaW5lX3N0YXR1cycsJ3ZvY0FscGhhJywndm9jRGVsdGEnLCdjb2xsZWN0aW9uX21vbnRoJywnc3VydmVpbGxhbmNlX3NhbXBsZScsJ0NUJywnbWVkaWFuX2NvdmVyYWdlJywncnVuJyldKQoKY3ZfbW9kZWwgPC0gY3YuZ2xtbmV0KHgsIHksIGFscGhhID0gMSwgbmZvbGRzPTEwMCkKcGxvdChjdl9tb2RlbCkgCmJlc3RfbW9kZWwgPC0gZ2xtbmV0KHgsIHksIGFscGhhID0gMSwgbGFtYmRhID0gY3ZfbW9kZWwkbGFtYmRhLm1pbikKYmVzdF9tb2RlbCRkZXYucmF0aW8KYGBgCgpgYGB7cn0KbGFzc28xX2FsdGRhdGEzPC1jb2VmKGJlc3RfbW9kZWwpICU+JSBhcy5tYXRyaXgoKSAlPiUgZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oKSAlPiUgcmVuYW1lKGZhY3Rvcj1yb3duYW1lLCBjb2VmZmljaWVudD1zMCkgJT4lIGZpbHRlcihmYWN0b3IhPSIoSW50ZXJjZXB0KSIpICU+JSBhcnJhbmdlKGRlc2MoY29lZmZpY2llbnQpKSAlPiUgZ2dwbG90KGFlcyh4PWNvZWZmaWNpZW50LCB5PWZjdF9yZW9yZGVyKGZhY3Rvcixjb2VmZmljaWVudCkpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD0iI0UyRDIwMCIsIGNvbG9yPSJncmF5IikgKyB0aGVtZV9idygpICsgeWxhYigiRmFjdG9yIikgKyB4bGFiKCJDb2VmZmljaWVudCIpCmBgYAoKYGBge3J9CiNzYW1lIG1vZGVsIGV4Y2x1ZGluZyBhbnkgZmFjdG9ycyB3aXRoIGEgdGVtcG9yYWwgc2lnbmFsIChWT0MsIHZhY2NpbmF0aW9uLCBjb2xsZWN0aW9uIG1vbnRoLCBydW4pCnkyPC1sb2cxMChwX3N1YiRuX3ZhcisxKQp4MjwtZGF0YS5tYXRyaXgocF9zdWJbLCBjKCdhZ2UxOHVuZGVyJywnYWdlNTVwbHVzJywnc2V4JywnY2hyb25pY19sdW5nX2Rpc2Vhc2UnLCAnY2hyb25pY19saXZlcl9kaXNlYXNlJywgJ2Nocm9uaWNfa2lkbmV5X2Rpc2Vhc2UnLCAnY2hyb25pY19oZWFydF9kaXNlYXNlJywgJ2h5cGVydGVuc2lvbicsICdkaWFiZXRlcycsICdjYW5jZXInLCAnb2Jlc2l0eScsICdwbGFzbWEnLCAnbUFiJywgJ2FkbWl0dGVkX2hvc3BpdGFsJywgJ3N1cnZlaWxsYW5jZV9zYW1wbGUnLCAnQ1QnLCAnbWVkaWFuX2NvdmVyYWdlJyldKQoKY3ZfbW9kZWxfMiA8LSBjdi5nbG1uZXQoeDIsIHkyLCBhbHBoYSA9IDEsIG5mb2xkcz0xMDApCnBsb3QoY3ZfbW9kZWxfMikgCmJlc3RfbW9kZWxfMiA8LSBnbG1uZXQoeDIsIHkyLCBhbHBoYSA9IDEsIGxhbWJkYSA9IGN2X21vZGVsJGxhbWJkYS5taW4pCmJlc3RfbW9kZWxfMiRkZXYucmF0aW8KYGBgCgpgYGB7cn0KbGFzc28yX2FsdGRhdGEzPC1jb2VmKGJlc3RfbW9kZWxfMikgJT4lIGFzLm1hdHJpeCgpICU+JSBkYXRhLmZyYW1lKCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSByZW5hbWUoZmFjdG9yPXJvd25hbWUsIGNvZWZmaWNpZW50PXMwKSAlPiUgZmlsdGVyKGZhY3RvciE9IihJbnRlcmNlcHQpIikgJT4lIGFycmFuZ2UoZGVzYyhjb2VmZmljaWVudCkpICU+JSBnZ3Bsb3QoYWVzKHg9Y29lZmZpY2llbnQsIHk9ZmN0X3Jlb3JkZXIoZmFjdG9yLGNvZWZmaWNpZW50KSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSIjRTJEMjAwIiwgY29sb3I9ImJsYWNrIikgKyB0aGVtZV9idygpICsgeWxhYigiRmFjdG9yIikgKyB4bGFiKCJDb2VmZmljaWVudCIpCmBgYAoKYGBge3J9CnRpdGxlIDwtIGdnZHJhdygpICsgCiAgZHJhd19sYWJlbCgKICAgICJBbHRlcm5hdGUgZGF0YXNldCAzIiwKICAgIGZvbnRmYWNlID0gJ2JvbGQnLAogICAgeCA9IDAsCiAgICBoanVzdCA9IDApCgphbGxfcGxvdHNfYWx0ZGF0YTM8LXBsb3RfZ3JpZChwbG90X2dyaWQoaG9zcF9hbHRkYXRhMywgdmF4X2FsdGRhdGEzLCBoY3dfYWx0ZGF0YTMsIG5jb2w9MyksIHBsb3RfZ3JpZChsYXNzbzFfYWx0ZGF0YTMsIGxhc3NvMl9hbHRkYXRhMywgbmNvbD0yKSwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoMiwxKSkKCmFsdF8zPC1wbG90X2dyaWQodGl0bGUsIGFsbF9wbG90c19hbHRkYXRhMywgbnJvdz0yLCByZWxfaGVpZ2h0cz1jKDAuMSwxKSkKYWx0XzMKYGBgCgoK